/**
 * JAVACC DEMO 1.0
 */
package com.apache.portal.common.restfull;

import com.apache.api.vo.ResultEntity;
import com.apache.api.vo.ResultMsg;
import com.apache.api.vo.Token;
import com.apache.cache.service.impl.LoadCacheFactory;
import com.apache.cache.util.Validator;
import com.apache.portal.common.annotion.BeanFactory;
import com.apache.portal.common.oscache.OsCacheManager;
import com.apache.portal.common.util.PortalPubFactory;
import com.apache.rpc.common.LoadRpcService;
import com.apache.rpc.entity.InterfaceRegister;
import com.apache.tools.ConfigUtil;
import com.apache.tools.RequestTools;
import com.apache.tools.StrUtil;
import com.apache.uct.common.LoginUser;
import com.apache.uct.common.PBOSSOTools;
import com.apache.uct.common.ToolsUtil;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.*;

/**
 * description:  客户端父类servlet
 *
 * @author Hou Dayu 创建时间：2016-4-11
 */
@SuppressWarnings("serial")
public abstract class SupperAction extends HttpServlet {

    protected Logger log = Logger.getLogger(getClass());

    protected abstract void doInvoke(HttpServletRequest request, HttpServletResponse response,
            String methodType) throws Exception;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //response.setCharacterEncoding("UTF-8")
        request.setCharacterEncoding("UTF-8");
        try {
            BeanFactory.getInstance().checkSysFlag();
            doInvoke(request, response, "get");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("执行请求出错：", e);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //response.setCharacterEncoding("UTF-8")
        request.setCharacterEncoding("UTF-8");
        try {
            BeanFactory.getInstance().checkSysFlag();
            doInvoke(request, response, "post");
        } catch (Exception e) {
            String methodName = request.getRequestURI() + ">>" + String
                    .valueOf(request.getAttribute("PathAttr0"));//方法名
            Map<String, String> params = getParameterMap(request);
            log.error("执行请求(" + methodName + ")出错,参数:" + params, e);

            log.error("执行请求出错：", e);
            e.printStackTrace();
        }
    }

    /**
     * description:  跳到登录页面
     */
    protected void gotoLogin(HttpServletRequest request, HttpServletResponse response, String msg)
            throws IOException {
        String header = request.getHeader("X-Requested-With");
        boolean isAjax = "XMLHttpRequest".equalsIgnoreCase(header) ? true : false;
        boolean isMobile = PortalPubFactory.getInstance().JudgeIsMoblie(request);
        if (isAjax || isMobile) {
            ResultMsg rmsg = new ResultMsg("F", StrUtil.doNull(msg, "您还没有登录，请您先登录再进行相应操作"));
            JSONObject array = JSONObject.fromObject(rmsg);
            this.outputJson(array.toString(), response, request.getParameter("callback"));
        } else {
            response.sendRedirect(request.getContextPath() + "/login.jsp");
        }
    }

    protected LoginUser getLoginUser(HttpServletRequest request, HttpServletResponse response) {
        LoginUser loginUser = null;
        boolean isMobile = PortalPubFactory.getInstance().JudgeIsMoblie(request);
        if (isMobile) {
            String tokenId = request.getParameter("tokenId");
            if (Validator.isNull(tokenId))
                return null;
            loginUser = OsCacheManager.getInstance().getLoginUser(tokenId);
            if (ToolsUtil.isEmpty(loginUser)) {
                loginUser = PBOSSOTools.getLoginUserFromUserCenterSso(tokenId);
                OsCacheManager.getInstance().putLoginUser(tokenId, loginUser);
            }
        } else {
            loginUser = PBOSSOTools.getLoginUser(request);
        }
        return loginUser;
    }

    /**
     * description:  跳到到错误页面
     */
    protected void gotoErrorPage(HttpServletRequest request, HttpServletResponse response,
            String errors) throws IOException, ServletException {
        String header = request.getHeader("X-Requested-With");
        boolean isAjax = "XMLHttpRequest".equalsIgnoreCase(header) ? true : false;
        boolean isMobile = PortalPubFactory.getInstance().JudgeIsMoblie(request);
        String clientCode = request.getParameter("userKeys");//来自客户端接口验证串
        if (isAjax || isMobile || StrUtil.isNotNull(clientCode)) {
            ResultMsg rmsg = new ResultMsg("F", StrUtil.doNull(errors, "请求的Action地址未定义"));
            JSONObject array = JSONObject.fromObject(rmsg);
            this.outputJson(array.toString(), response, request.getParameter("callback"));
        } else {
            request.setAttribute("errors", "请求的Action地址未定义");
            request.getRequestDispatcher("/doSendPage?toPage=error").forward(request, response);
        }
    }

    /**
     * description:  获取请求参数
     */
    @SuppressWarnings("rawtypes")
    protected Map<String, String> getParameterMap(HttpServletRequest request) throws IOException {
        String ifBatch = StrUtil.doNull(request.getParameter("ifBatch"), "F");
        Map<String, String> map = new HashMap<String, String>();
        String reqIp = RequestTools.getIp(request);
        map.put("Client-IP", reqIp);
        Set keSet = request.getParameterMap().entrySet();
        for (Iterator itr = keSet.iterator(); itr.hasNext(); ) {
            Map.Entry me = (Map.Entry) itr.next();
            String ok = String.valueOf(me.getKey());
            if ("ifBatch".equalsIgnoreCase(ok))
                continue;
            Object ov = me.getValue();
            String value = "";
            if (ov instanceof String[]) {
                String[] vls = (String[]) ov;
                if ("F".equalsIgnoreCase(ifBatch)) {//单表插入
                    value = vls[0];
                } else {
                    for (int i = 0; i < vls.length; i++) {////批量处理
                        if (i == vls.length - 1) {
                            value += StrUtil.doNull(vls[i], "_");
                        } else {
                            value += StrUtil.doNull(vls[i], "_") + "-#-";
                        }
                    }
                }
            } else {
                value = String.valueOf(ov);
            }
            log.info(ok+"->" + value);
            if (StrUtil.isNotNull(value)) {
                String str = new String(value.getBytes("iso8859-1"), "iso8859-1");
                if (value.equals(str)) {
                    value = str;
                }
                map.put(ok, value);
            } else {
                if (ok.indexOf("s_") != -1) {
                    map.put(ok, "is null");//清空
                }
            }
        }
        map.put("sysPass", ConfigUtil.getInstance().interfacePass());
        return map;
    }

    /**
     * 输出json数据
     *
     * @param json
     * @param response
     */
    protected void outputJson(String json, HttpServletResponse response, String callback)
            throws IOException {
        if (StrUtil.isNotNull(json)) {
            PrintWriter out = response.getWriter();
            if (StrUtil.isNull(callback)) {
                response.setContentType("text/html;charset=UTF-8");
                /**
                 * 解决外部系统跨域访问，Access-Control-Allow-Origin的提示
                 * xhe 20171107
                 * 思路来自：http://blog.csdn.net/fdipzone/article/details/46390573/
                 */
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Methods", "POST,GET");
                response.setHeader("Access-Control-Allow-Credentials", "true");
                out.print(json);
            } else {
                response.setContentType("application/javascript");
                out.print(callback + "(" + json + ")");
            }
            out.flush();
            out.close();
        }
    }

    /**
     * 反射调用类方法32
     *
     * @return 返回方法执行结果
     */
    @SuppressWarnings({ "rawtypes" })
    protected Method doInvoke(Class queryclass, HttpServletRequest request,
            HttpServletResponse response, String methodType, String doCode)
            throws NullPointerException, SecurityException {
        Method[] methods = queryclass.getDeclaredMethods();// 获得类的方法集合
        Method method = null;
        String methodName = StrUtil
                .doNull(String.valueOf(request.getAttribute("PathAttr0")), doCode);//方法名
        if (methods != null) {
            Method defMethod = null;
            int count = methods.length;
            for (int i = 0; i < count; i++) {
                if (methods[i].isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping rm = (RequestMapping) methods[i]
                            .getAnnotation(RequestMapping.class);
                    if (rm.value().equals(methodName)) {
                        if (ToolsUtil.isNull(rm.method())) {
                            method = methods[i];
                            break;
                        } else if (methodType.equalsIgnoreCase(rm.method())) {
                            method = methods[i];
                            break;
                        }
                    }
                    if ((ToolsUtil.isNull(rm.value())) && (methodType
                            .equalsIgnoreCase(rm.method()))) {
                        defMethod = methods[i];
                    }
                }
            }
            if (null == method && null != defMethod) {
                method = defMethod;
            }
        }
        return method;
    }

    protected ResultMsg getResultMsg(HttpServletRequest request, String msg) {
        request.getSession().setAttribute("formToken", request.getAttribute("formToken"));
        ResultMsg rmsg = new ResultMsg("F", msg);
        return rmsg;
    }

    /**
     * description: 验证令牌是否有效,以防止表单重复提交
     */
    protected boolean checkToken(HttpServletRequest request, Method method) {
        if (null != method) {
            Token annotation = method.getAnnotation(Token.class);
            if (annotation != null) {
                boolean needRemoveSession = annotation.remove();
                if (needRemoveSession) {//移出token
                    if (isRepeatSubmit(request)) {
                        return false;
                    }
                    request.setAttribute("formToken",
                            request.getSession(false).getAttribute("formToken"));
                    request.getSession(false).removeAttribute("formToken");
                }
            }
        }
        return true;
    }

    /**
     * 判断是否重复提交
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        String serverToken = Validator
                .getDefaultStr(String.valueOf(request.getSession(false).getAttribute("formToken")),
                        "");
        if (Validator.isNull(serverToken)) {
            return true;
        }
        String clinetToken = request.getParameter("formToken");
        if (Validator.isNull(clinetToken)) {
            return true;
        }
        if (!serverToken.equals(clinetToken)) {
            return true;
        }
        return false;
    }

    /**
     * description: 发送消息
     */
    protected void sendNotice(HttpServletRequest request, String formUser, String toUser,
            String noticeTitle, String objId, String message) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("noticeStatus", "0");
        params.put("noticeTitle", noticeTitle);
        params.put("userEname", toUser);
        params.put("noticeContent", message);
        params.put("createdUser", formUser);
        params.put("objId", objId);
        params.put("doCode", "R0001");
        params.put("sortCode", "notice");
        PortalPubFactory.getInstance().getPlugin("info").doInvoke(request, null, params);
    }

    /**
     * 跨数据源RPC操作，查询业务表数据信息
     * @param datasource 指定系统所属数据源，如平台的plateform
     * @param modelTypes 指定要查询的表对象，如s_uctUser
     * @param resultObjType 返回值类型 list/count
     * @param whereMap 拼装查询条件[格式如：对象.w_属性=值/对象.wl_属性=值]，如whereMap.put("uctUser.w_userSex","F");
     * @return
     */
    public ResultEntity selectInfoForDatasource(String datasource, String modelTypes, String resultObjType, Map<String, Object> whereMap) {
        whereMap.put("datasource", datasource);
        whereMap.put("modelTypes", modelTypes);
        whereMap.put("resultObjType", resultObjType);
        whereMap.put("resultType", "objInfo");
        if (null == whereMap.get("sqlKeyId")) {
            whereMap.put("sqlKeyId", "sqlKeyId");
        }
        whereMap.put("sysPass", ConfigUtil.getInstance().interfacePass());
        log.info("请求参数：" + whereMap);
        InterfaceRegister register = new InterfaceRegister();
        register.setAddress("127.0.0.1");
        register.setCallType("socket");
        return LoadRpcService.service().doServiceClient(getBeanId(datasource), "dymicSql", whereMap, register);
    }

    private String getBeanId(String datasourceName) {
        String beanId = "iusService";
        if (StrUtil.isNotNull(datasourceName)) {
            if ("cms".equals(datasourceName)) {
                beanId = "websiteService";
            } else {
                beanId = datasourceName + "Service";
                if (!isExites(beanId) || "memberService".equals(beanId)) {
                    beanId = "iusService";
                }
            }
        }
        return beanId;
    }
    private boolean isExites(String beanId) {
        if (StrUtil.isNull(beanId))
            return false;
        String cacheKey = "interfaceRegister_" + beanId;
        return LoadCacheFactory.getInstance().getCacheManager("").checkCacheObject(cacheKey);
    }

    protected Map getDefaultDataMap(HttpServletRequest request) {
        Map<String, Object> parmMap = new HashMap();
        Map<String, String> mapConfig = new HashMap();
        Map cfMap = ConfigUtil.getInstance().getLocalByKey("config.properties");
        if (cfMap != null) {
            mapConfig.putAll(cfMap);
        }

        parmMap.put("config", mapConfig);
        parmMap.put("ctx", request.getContextPath());
        parmMap.put("formToken", UUID.randomUUID().toString());
        return parmMap;
    }
}
